Android SQLite数据库升级解决方案
在使用SQLite数据库的时候,一般会有数据库版本的迭代。例如APP首次开发完成,数据库的版本是1.0版,然后需求增加,需要对数据库做改动,这时候数据库的版本就要更新为2.0。SQLite在遇见版本升级时会对比旧版本号和新版本号,执行onUpgrade()方法,需要自己在onUpgrade()方法中实现相应的逻辑。
SQLite版本升级的逻辑是:如果设备是首次安装这个APP,那么只会执行onCreate()方法;如果设备中安装有这个APP的旧版本,在安装新版本时,不会执行onCreate()方法,而只会执行onUpgrade()方法。
举个栗子
在数据库第一个版本中,我们新建一个people表,数据库版本号为1,SQLiteHelper类如下:
public class SQLiteHelper extends SQLiteOpenHelper {
private static SQLiteHelper instance;
private static final String DATABASE_NAME = "local_db";
//初始版本号,固定不变
private static final int FIRST_VERSION = 1;
public static SQLiteHelper getInstance(Context context){
if (instance == null){
instance = new SQLiteHelper(context, DATABASE_NAME, null, NEW_VERSION);
}
return instance;
}
public SQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
//初始化时新建people表
sqLiteDatabase.execSQL("create table if not exists people(" +
"name text not null)");
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
}
}
之后我们有了新的需求,需要再建一个job表,这时数据库的版本号升级为2,而且我们需要在onUpgrade()方法中加入相关代码。
public class SQLiteHelper extends SQLiteOpenHelper {
private static SQLiteHelper instance;
private static final String DATABASE_NAME = "local_db";
//初始版本号,固定不变
private static final int FIRST_VERSION = 1;
//新的版本号
private static final int NEW_VERSION = 2;
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
//初始化时新建people表
sqLiteDatabase.execSQL("create table if not exists people(" +
"name text not null)");
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
if (oldVersion == 1){
sqLiteDatabase.execSQL("create table if not exists job(" +
"title text)");
}
}
}
在onUpgrade()方法中,我们判断旧版本号如果为1的话就执行新的建表语句。这样可以解决从版本1升级到版本2的问题,但是如果用户直接从版本2开始安装呢?首次安装是不会执行onUpgrade()方法的,所以新的建表语句无法被执行到。对于这个问题,我们可以在onCreate()方法中手动调用onUpgrade()方法,oldVersion传入初始版本号,newVersion传入当前最新版本号:
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
//初始化时新建people表
sqLiteDatabase.execSQL("create table if not exists people(" +
"name text not null)");
onUpgrade(sqLiteDatabase, FIRST_VERSION, NEW_VERSION);
}
现在APP的数据库版本为2,这时我们又有了新的需求,需要新建一个company表。首先考虑从版本2升级到版本3的问题,那么在onUpgrade()方法中这样添加:
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
if (oldVersion == 1){
sqLiteDatabase.execSQL("create table if not exists job(" +
"title text)");
}
if (oldVersion == 2){
sqLiteDatabase.execSQL("create table if not exists groups(" +
"name text not null)");
}
}
这样如果oldVersion为2,就会执行新的建表语句。但是如果oldVersion是1呢,从1直接升级到3,目前只会执行if(oldVersion == 1)中的语句。对于这个问题,有些解决方案是添加多个判断,把所有情况考虑完,比如1=>2、1=>3、2=>3,这3种情况下执行不同的操作,但是这样的话不仅麻烦,而且随着数据库版本的迭代,所要考虑的情况会越来越多。
对于这种情况,我的解决办法是使用递归的方式,从当前最老的版本开始,每次只考虑1个版本的间隔,一级一级的升级:
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
if (oldVersion == 1){
sqLiteDatabase.execSQL("create table if not exists job(" +
"title text)");
}
if (oldVersion == 2){
sqLiteDatabase.execSQL("create table if not exists groups(" +
"name text not null)");
}
//递归调用
if (newVersion-oldVersion > 1){
onUpgrade(sqLiteDatabase, oldVersion+1, newVersion);
}
}
在递归的过程中,旧版本不断的+1,一直到和新版本只相差1,完成所有的升级操作。
完整的示例
public class SQLiteHelper extends SQLiteOpenHelper {
private static SQLiteHelper instance;
private static final String DATABASE_NAME = "local_db";
private static final int FIRST_VERSION = 1;
private static final int NEW_VERSION = 4;
public static SQLiteHelper getInstance(Context context){
if (instance == null){
instance = new SQLiteHelper(context, DATABASE_NAME, null, NEW_VERSION);
}
return instance;
}
public static SQLiteDatabase getWritableDatabase(Context context){
return getInstance(context).getWritableDatabase();
}
public static SQLiteDatabase getReadableDatabase(Context context){
return getInstance(context).getReadableDatabase();
}
public SQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("create table if not exists people(" +
"name text not null)");
onUpgrade(sqLiteDatabase, FIRST_VERSION, NEW_VERSION);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
if (oldVersion == 1){
sqLiteDatabase.execSQL("create table if not exists job(" +
"title text)");
}
if (oldVersion == 2){
sqLiteDatabase.execSQL("create table if not exists groups(" +
"name text not null)");
}
if (oldVersion == 3){
sqLiteDatabase.execSQL("create table if not exists company(" +
"name text not null)");
}
if (newVersion-oldVersion > 1){
onUpgrade(sqLiteDatabase, oldVersion+1, newVersion);
}
}
}